/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package ssp.net;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import ssp.topology.Node;
import ssp.utility.MersenneTwisterRNG;
import ssp.utility.PropertyManager;

/**
 * NWresourceEntryを生成してネットワークコンポーネントに割り当てるためのクラス
 * @author yamazaki
 */
public class NWresourceFactory {
    
    /**
     * ネットワークコンポーネントに資源を割り当てる
     * @param QoSnum QoS指標の数
     * @param QoSrange QoS指標の幅
     */
    public static void allocateNWresource(int QoSnum, int QoSrange, double QoSmax) {
        
        double bandwidthUnit = PropertyManager.getValueAsDouble("BandwidthUnit");
        int capacity = PropertyManager.getValueAsInteger("Bandwidth");
    
        List<Node> neighbors = new ArrayList<>();
        for(NWcomponent nwComponent : NWcomponentManager.getINSTANCE().getNWcomponentList()) {
            neighbors.addAll(nwComponent.getNeighborNWcomponents());
            
            int localCapacity = (int)Math.ceil(capacity / neighbors.size());
            
            int neighborsSize = neighbors.size();
            Set<Node> connectedNode = new HashSet<>();
            for(int i=0 ; i<neighborsSize ; i++) {
                for(int j=i+1 ; j<neighborsSize ; j++) {
                    
                    connectedNode.add(neighbors.get(i));
                    connectedNode.add(neighbors.get(j));
                    
                    List<Double> QoSindexList = new ArrayList<>(makeQoS(QoSnum, QoSrange, QoSmax));
                    
                    nwComponent.getNWresourceManager().addNWresourceEntry(new NWresourceEntry(connectedNode, bandwidthUnit, makecharge(bandwidthUnit, QoSindexList), QoSindexList, localCapacity));
                    connectedNode.clear();
                }
            }
            neighbors.clear();
        }
    }
    
    /**
     * 指定数のQoS指標を生成
     * @param QoSnum QoSの数
     * @param QoSrange QoSの幅
     * @return 
     */
    private static List<Double> makeQoS(int QoSnum, int QoSrange, double QoSmax) {
        double delta = (double)(QoSmax - 1.0) / QoSrange;
        List<Double> QoSindexList = new ArrayList<>();
        for(int i=0 ; i<QoSnum ; i++) {
            QoSindexList.add(MersenneTwisterRNG.getINSTANCE().nextInt(QoSrange) * delta + 1.0);
        }
        return QoSindexList;
    }
    
    /**
     * QoS指標を元に利用料金を生成
     * @param bandwidthUnit 通威信帯域の最小単位
     * @param QoSindexList QoS指標のリスト
     * @return 利用料金
     */
    private static double makecharge(double bandwidthUnit, List<Double> QoSindexList) {
        double charge = bandwidthUnit * MersenneTwisterRNG.getINSTANCE().nextDouble() / (PropertyManager.getValueAsDouble("ServiceTimeBase") * 0.5) * 1.0;
        for(double qos : QoSindexList) {
            charge += qos * MersenneTwisterRNG.getINSTANCE().nextDouble() / (PropertyManager.getValueAsDouble("ServiceTimeBase") * 0.5) * 1.0;
        }
        return charge;
    }
    
}
